home *** CD-ROM | disk | FTP | other *** search
/ PC Graphics Unleashed / PC Graphics Unleashed.iso / ch05 / dither.c < prev    next >
C/C++ Source or Header  |  1994-08-08  |  15KB  |  397 lines

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<conio.h>
  4. #include<fcntl.h>
  5. #include<io.h>
  6. #include<vsa.h>
  7. #include<vsa_font.h>
  8. #include<tiff.h>
  9.  
  10. #ifndef _MSC_VER
  11. /*.....                This is line for Borland C Only !               .....*/
  12. extern unsigned _stklen = 13000;
  13. #endif
  14.  
  15. void     draw_dithered_pixel(int,int,unsigned char *,int);
  16. int      crack_rgb(unsigned char *,int *,int *,int *,float *,
  17.                                      float *,float *);
  18. unsigned long read_tga_header(int,int *,int *,int *,int *);
  19. void     true_color_lut(void);
  20. void     vsa_get_input(char *);
  21. void          update_message(int,int,int,char *);
  22. void     clear_text_area(int,int,int,int);
  23. void     color_bar(int,int);
  24.  
  25. unsigned char dither[4][64]={
  26. {
  27.  1 },
  28. {
  29.  1, 3,
  30.  4, 2 },
  31. {
  32.  1,  9, 3, 11,
  33. 13,  5, 15, 7,
  34.  4, 12, 2, 10,
  35. 16,  8, 14, 6 },
  36. {
  37.  1, 33,  9, 41,  3, 35, 11, 43,
  38. 49, 17, 57, 25, 51, 19, 59, 27,
  39. 13, 45,  5, 37, 15, 47,  7, 39,
  40. 61, 29, 53, 21, 63, 31, 55, 23,
  41.  4, 36, 12, 44,  2, 34, 10, 42,
  42. 52, 20, 60, 28, 50, 18, 58, 26,
  43. 16, 48,  8, 40, 14, 46,  6, 38,
  44. 64, 32, 56, 24, 62, 30, 54, 22 },
  45. };
  46.  
  47. /*......................... DITHER.C............. 5-29-94 .....*/
  48. /* This program reads True Color (24 bit per pixel) TARGA      */
  49. /* images and converts them to 8 bit dithered screen images.   */
  50. /* It also writes out the dithered image as an 8 bit per pixel */
  51. /* Palette Color TIFF image.                                   */
  52. /*.............................................................*/
  53. void main(int argc, char *argv[])
  54. {
  55.     char filename[80],text[100];
  56.     int i,j,size,width,height,type,file_handle,orient,vmode;
  57.     int r0,c0;
  58.     unsigned char rgb[3072];
  59.     if(argc > 1)
  60. /*.............................................................*/
  61. /*          If specified, set requested video  mode.           */
  62. /*.............................................................*/
  63.         {
  64.             sscanf(argv[1],"%x",&vmode);
  65.             if(vsa_init(vmode) != 0)
  66.                     {
  67.                         printf("Can't set Requested VESA video mode!\n");
  68.                         printf("Is VESA BIOS Extension TSR loaded?\n");
  69.                         return;
  70.                     }
  71.         }
  72.     else
  73. /*.............................................................*/
  74. /*     Otherwise set highest video resolution available.       */
  75. /*.............................................................*/
  76.         {
  77.             if(vsa_init(0x105) != 0)             /* 1024 x 768 x 256 */
  78.                 if(vsa_init(0x103) != 0)           /*  800 x 600 x 256 */
  79.                     if(vsa_init(0x101) != 0)         /*  640 x 480 x 256 */
  80.                         if(vsa_init(0x100) != 0)       /*  640 x 400 x 256 */
  81.                             {
  82.                                 printf("Can't set VESA video mode!\n");
  83.                                 printf("Is VESA BIOS Extension TSR loaded?\n");
  84.                                 return;
  85.                             }
  86.         }
  87. /*.............................................................*/
  88. /*       Set up the Palette as an 8 bit RGB (3,3,2) table.     */
  89. /*       and draw color look up table.                         */
  90. /*.............................................................*/
  91.     true_color_lut();
  92.     tf_set_prime_colors();
  93.     color_bar(0.125*XResolution,0.91*YResolution);
  94. /*..........................................................................*/
  95. /*                        Draw Frame around screen.                         */
  96. /*..........................................................................*/
  97.     vsa_set_color(TF_Blue);
  98.     vsa_move_to(0,0);
  99.     vsa_rect(XResolution-1,YResolution-1);
  100. /*..........................................................................*/
  101. /*            Set up text cursor mode and location.                         */
  102. /*..........................................................................*/
  103.     vsa_set_text_cursor_mode(1);
  104.     r0 = 0.85*YCharResolution;
  105.     c0 = 0.5*XCharResolution - 17;
  106. /*..........................................................................*/
  107. /*       Enter main loop which displays dithered images.                    */
  108. /*..........................................................................*/
  109. LOOP:
  110.     update_message(c0*XCharSize,r0*YCharSize,TF_Green,"Input TARGA Image Filename: ");
  111.     vsa_get_input(filename);
  112.     if(filename[0] == 0)
  113.         goto BAIL;
  114. /*.............................................................*/
  115. /* Get dither size and limit it to legal value of 1,2,4 or 8.  */
  116. /*.............................................................*/
  117.     update_message(c0*XCharSize,(r0+1)*YCharSize,TF_Green,"Input Dither Size (1, 2, 4, or 8): ");
  118.     vsa_get_input(text);
  119.     sscanf(text,"%d",&size);
  120.     if(size == 3) size = 4;     /* size limited to 1, 2, 4, or 8 */
  121.     if(size > 4)  size = 8;     /* size limited to 1, 2, 4, or 8 */
  122. /*.............................................................*/
  123. /*           Open the TARGA file and get header info.          */
  124. /*.............................................................*/
  125.     if((file_handle = open(filename,O_BINARY | O_RDONLY)) == -1)
  126.         {
  127.             sprintf(text,"Can't find file %s",filename);
  128.             update_message(c0*XCharSize,r0*YCharSize,TF_Red,text);
  129.             update_message(c0*XCharSize,(r0+1)*YCharSize,TF_Red,"");
  130.             getch();
  131.             goto LOOP;
  132.         }
  133.     update_message(c0*XCharSize,r0*YCharSize,TF_Violet,"Generating Dithered Image.");
  134.     update_message(c0*XCharSize,(r0+1)*YCharSize,TF_Red,"");
  135.     read_tga_header(file_handle,&width,&height,&type,&orient);
  136. /*.............................................................*/
  137. /*              Draw Frame around the new picture.             */
  138. /*.............................................................*/
  139.     vsa_set_color(TF_White);
  140.     vsa_move_to(2,2);
  141.     vsa_rect(width+3,height+3);
  142. /*.............................................................*/
  143. /*  Read out pixels from TARGA file and plot on screen in      */
  144. /*  top down or bottom up order depending on orientation.      */
  145. /*.............................................................*/
  146.     if(orient == 32)
  147.         for(j=0;j<height;j++)
  148.             {
  149.                 read(file_handle,rgb,3*width);
  150.                 for(i=0;i<width;i++)
  151.                     draw_dithered_pixel(i+3,j+3,rgb+3*i,size);
  152.             }
  153.     else
  154.         for(j=height-1;j>=0;j--)
  155.             {
  156.                 read(file_handle,rgb,3*width);
  157.                 for(i=0;i<width;i++)
  158.                     draw_dithered_pixel(i+3,j+3,rgb+3*i,size);
  159.             }
  160.     color_bar(0.125*XResolution,0.91*YResolution);
  161. /*.............................................................*/
  162. /*  Close the image file and look for an ESC key to quit.      */
  163. /*  Otherwise, save dithered image as an 8 bit TIFF called     */
  164. /*  NEW.TIF and LOOP for experimentation with a different      */
  165. /*  dither box size.                                           */
  166. /*.............................................................*/
  167.     close(file_handle);
  168.     update_message(c0*XCharSize,r0*YCharSize,TF_Red,
  169.                                  "ESC to quit, any other key to continue.");
  170.     update_message(c0*XCharSize,(r0+1)*YCharSize,TF_Yellow,"");
  171.     if(getch() == 27)
  172.         goto BAIL;
  173.     update_message(c0*XCharSize,r0*YCharSize,TF_Blue,
  174.                                  "Saving image as NEW.TIF.");
  175.     tf_save_file(0,0,width-1,height-1,"new.tif");
  176.     goto LOOP;                    /*.....   Oh No, a goto!  .....*/
  177. BAIL:
  178.     vsa_about();
  179.     getch();
  180.     vsa_set_svga_mode(0x3);
  181.     return;                       /*.....   End main        .....*/
  182. }
  183.  
  184. /*.................... DRAW_DITHERED_PIXEL ....... 5-27-94 ....*/
  185. /* This routine draws a dithered pixel at screen coordinate    */
  186. /* 'i,j' with 24 bit color equivalent passed in the 3 byte     */
  187. /* array 'rgb'.  The dither pattern size is specified by 'size'*/
  188. /* and can be 1, 2, 4, or 8.  Note that the global 'dither'    */
  189. /* array must must be initialized before calling this routine. */
  190. /*.............................................................*/
  191. void draw_dithered_pixel(int i,int j,unsigned char *rgb,int size)
  192. {
  193.   int n,m,q,r,red_lvl,grn_lvl,blu_lvl;
  194.   int color,red_boost,grn_boost,blu_boost;
  195.     float x,y,frl,fgl,fbl;
  196. /*.............................................................*/
  197. /* For the pixels screen address i,j, compute pixel address r  */
  198. /* within the dither box.  Also select dither box q based on   */
  199. /* size (size = 1, 2, 4, or 8).                                */
  200. /*.............................................................*/
  201.   x = (float)i/size;
  202.   y = (float)j/size;
  203.   m = (int)(size*(x - (int)x) + 0.5);
  204.   n = (int)(size*(y - (int)y) + 0.5);
  205.   q = size/2;
  206.   if(size == 8) q = 3;
  207.   r = m+n*size;
  208. /*.............................................................*/
  209. /* Get the Dark Pixel color, the Light Pixel components, and   */
  210. /* the pixel color errors.                                     */
  211. /*.............................................................*/
  212.   color = crack_rgb(rgb,&red_boost,&grn_boost,&blu_boost,
  213.                     &frl,&fgl,&fbl);
  214. /*.............................................................*/
  215. /*Scale the pixel color error values based on dither box size  */
  216. /*.............................................................*/
  217.   red_lvl = size*size*frl;
  218.   grn_lvl = size*size*fgl;
  219.   blu_lvl = size*size*fbl;
  220. /*.............................................................*/
  221. /*Test the pixels red, green, and blue error values against the*/
  222. /*thresholds in the dither box.  Decide which color to use.    */
  223. /*.............................................................*/
  224.   if(dither[q][r] <= red_lvl)
  225.     color = (color & 0x1f) + (red_boost << 5);    /* Boost Red */
  226.   if(dither[q][r] <= grn_lvl)
  227.     color = (color & 0xe3) + (grn_boost << 2);    /* Boost Grn */
  228.   if(dither[q][r] <= blu_lvl)
  229.     color = (color & 0xfc) + blu_boost;           /* Boost Blu */
  230. /*.............................................................*/
  231. /*              Set color and draw pixel on screen.            */
  232. /*.............................................................*/
  233.   vsa_set_color(color);
  234.     vsa_set_pixel(i,j);
  235.   return;
  236. }                           /*.... END draw_dithered_pixel ....*/
  237.  
  238.  
  239. /*.......................... CRACK_RGB ........... 5-27-94 ....*/
  240. /* This routine takes the 24 bit RGB color value in the 'rgb'  */
  241. /* array, quantizes it down to an 8 bit color value (3 bit red,*/
  242. /* 3 bit green, and 2 bit blue) and returns this 8 bit         */
  243. /* 'base_color' value. It also computes the 8 bit color boost  */
  244. /* values '*red_boost', 'grn_boost', and 'blu_boost' which are */
  245. /* used to draw dithered pixels.  It also computes the color   */
  246. /* error values 'red_lvl', 'grn_lvl', and 'blu_lvl' which      */
  247. /* determine when the dither function draws with 'base_color'  */
  248. /* and when it draws with 'xxx_boost' color.                   */
  249. /*.............................................................*/
  250. int crack_rgb(unsigned char *rgb,int *red_boost,int *grn_boost,
  251.               int *blu_boost,float *red_lvl,float *grn_lvl,
  252.               float *blu_lvl)
  253. {
  254.   int   base_color,red,grn,blu;
  255.   float fred,fgrn,fblu;
  256.  
  257.   fred = rgb[2]/36.6;   /*36.6 = (256 shades of red)/(2^3 - 1) */
  258.   fgrn = rgb[1]/36.6;   /*36.6 = (256 shades of grn)/(2^3 - 1) */
  259.   fblu = rgb[0]/85.4;   /*85.4 = (256 shades of blu)/(2^2 - 1) */
  260.  
  261.   red = fred;
  262.   grn = fgrn;
  263.   blu = fblu;
  264.   base_color = (red << 5)+(grn << 2)+blu;   /*Dark Pixel color */
  265.  
  266.   *red_lvl = fred - red;
  267.   *grn_lvl = fgrn - grn;
  268.   *blu_lvl = fblu - blu;
  269.  
  270.   *red_boost = red+1;  /*This is the Light Pixel color for red */
  271.   *grn_boost = grn+1;  /*This is the Light Pixel color for grn */
  272.   *blu_boost = blu+1;  /*This is the Light Pixel color for blu */
  273.  
  274.   return base_color;
  275. }                           /*.... END crack_rgb          .....*/
  276.  
  277.  
  278. /*....................... READ_TGA_HEADER  ....... 5-17-94 ....*/
  279. /* This routine parses through a TGA header and returns the    */
  280. /* file offset in bytes to the first byte of pixel data.       */
  281. /* It also returns image width, height, and type (type 2 is the*/
  282. /* uncompressed 24 bit image type).                            */
  283. /*.............................................................*/
  284. unsigned long read_tga_header(int handle, int *width,
  285.                                                             int *height, int *type,
  286.                                                             int *orientation)
  287. {
  288.   unsigned long offset;
  289.   unsigned char buff[18];
  290.   read(handle,buff,18);
  291.   offset = 18+buff[0];
  292.   *type = buff[2];
  293.  
  294.   *width  = *((unsigned *)buff + 6);
  295.   *height = *((unsigned *)buff + 7);
  296.     *orientation = buff[17];
  297.     return offset;
  298. }                           /*.... END read_tga_header    .....*/
  299.  
  300. /*.................... TRUE_COLOR_LUT.C .......... 5-15-94 ....*/
  301. /* This routine generates a 'true color' LUT.  An 8 bit index  */
  302. /* into the LUT represents 3 bits of RED, 3 bits of GREEN, and */
  303. /* 2 bits of BLUE.  The 3 msbs of the 8 bit index are the RED  */
  304. /* field, next 3 are GREEN, and the 2 lsbs are the BLUE field. */
  305. /*                                                             */
  306. /*.............................................................*/
  307. void true_color_lut(void)
  308. {
  309.     int i;
  310.     unsigned char color_array[768];
  311.     for(i=0;i<256;i++)
  312.         {
  313.             color_array[3*i+0]= ((i & 0x00e0) >> 5) * 9;
  314.             color_array[3*i+1]= ((i & 0x001c) >> 2) * 9;
  315.             color_array[3*i+2]= (i & 0x0003) * 21;
  316.         }
  317.     vsa_write_color_block(0,256,color_array);
  318.     return;
  319. }                          /*.....   End true_color_lut   .....*/
  320.  
  321. void update_message(int x0,int y0,int color,char *text)
  322. {
  323.     clear_text_area(x0,y0,51,TF_Black);
  324.     vsa_write_string(x0,y0,color,text);
  325.     vsa_set_color(color);
  326.     return;
  327. }
  328.  
  329. void clear_text_area(int x0,int y0,int length,int color)
  330. {
  331.     vsa_set_color(color);
  332.     vsa_move_to(x0,y0);
  333.     vsa_rect_fill(x0+length*XCharSize-1,y0+YCharSize-1);
  334.     return;
  335. }
  336.  
  337. /*.......................... VSA_GET_INPUT .................... 6-25-94 ....*/
  338. /*  This routine reads the keyboard input and echos it to the screen until  */
  339. /* a carriage return is entered. Then the whole text string is returned     */
  340. /* via 'text'.                                                              */
  341. /*..........................................................................*/
  342. void vsa_get_input(char *text)
  343. {
  344.     int i,x,y;
  345.     char key;
  346.     vsa_get_text_cursor(&x,&y);
  347.     i=0;
  348.     text[0] = 0;
  349.     key = getch();
  350.     while((key != 13) && (key != 27))                     /*  Do until a return          */
  351.         {                                        /*  or an ESCAPE Key is hit.   */
  352.             if(key != 8)
  353.                 {                                    /*  If not a back space        */
  354.                     text[i] = key;                     /*  add key entry to string.   */
  355.                     text[i+1] = 0;
  356.                     vsa_write_string(x,y,TF_White,text);/*  Echo the updated string.   */
  357.                     i++;
  358.                 }
  359.             else
  360.                 {                                    /*  If a back space            */
  361.                     if(i > 0) i --;                    /*  delete last key entry.     */
  362.                     text[i] = 92;
  363.                     vsa_write_string(x,y,TF_White,text);/*  Echo the updated string.   */
  364.                     text[i] = 0;
  365.                 }
  366.             key = getch();
  367.         }
  368.     return;
  369. }
  370.  
  371. void color_bar(x0,y0)
  372. int x0,y0;
  373. {
  374.     int i;
  375.     unsigned xx,yy,a,b;
  376.     float c;
  377.     xx = XResolution;
  378.     yy = YResolution;
  379. /*..........................................................................*/
  380. /*     Draw outline for color bar.                                          */
  381. /*..........................................................................*/
  382.     vsa_set_color(15);
  383.     vsa_move_to(x0-1,y0-1);
  384.     a = .75*xx;
  385.     b = .065*yy;
  386.     vsa_rect(x0+a+1,y0+b+1);
  387.     c = (float)a/256;
  388.     for(i=0;i<256;i++)
  389.         {
  390.             vsa_set_color((unsigned char)i);
  391.             vsa_move_to(x0+(unsigned)(i*c),y0);
  392.             vsa_rect_fill(x0+(unsigned)(c+i*c),y0+b);
  393.         }
  394.     return;
  395. }
  396.  
  397.